home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -serious- / programming / other / evaluate / evaluate.c < prev    next >
C/C++ Source or Header  |  2000-02-28  |  23KB  |  814 lines

  1. /* evaluate.c (C) 2000 Kyzer/CSG.
  2. /* Released under the terms of the GNU General Public Licence version 2. */
  3.  
  4. #include <ctype.h>
  5. #include <limits.h>
  6. #include <math.h>
  7. #include <stddef.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. /*** CONSTANTS ***/
  12.  
  13. /* error codes */
  14. #include "evaluate.h"
  15.  
  16. /* value types */
  17. enum {
  18.   T_INT  = RESULT_INTEGER,
  19.   T_REAL = RESULT_REAL
  20. };
  21.  
  22.  
  23. /* token types */
  24. enum {
  25.   /* parentheses */
  26.   TK_OPEN, TK_CLOSE,
  27.  
  28.   /* variables and values */
  29.   TK_VAR, TK_VAL,
  30.  
  31.   /* binary operators */
  32.   TK_ADD, TK_SUB, TK_MUL, TK_MULI, TK_DIV,
  33.   TK_MOD, TK_POW, TK_AND, TK_OR, TK_BAND,
  34.   TK_BOR, TK_BXOR, TK_EQ, TK_NE, TK_LT, TK_GT,
  35.   TK_LE, TK_GE, TK_SHL, TK_SHR,
  36.  
  37.   /* unary operators */
  38.   TK_ASSN, TK_NEG, TK_FUNC, TK_NOT, TK_BNOT,
  39.  
  40.   /* special scan codes */
  41.   TK_BREAK, /* finish scanning, bring remainder of string forward */
  42.   TK_ERROR, /* abort scanning */
  43.   TK_SKIP   /* ignore the character */
  44. };
  45.  
  46. /* function ids (index to functable) */
  47. enum {
  48.   F_ACOS, F_ASIN, F_ATAN, F_COS, F_COSH, F_EXP, F_LN, F_LOG,
  49.   F_SIN, F_SINH, F_SQR, F_SQRT, F_TAN, F_TANH
  50. };
  51.  
  52.  
  53. /*** STRUCTURES ***/
  54.  
  55. struct val {
  56.   long   ival;
  57.   double rval;
  58.   char   type; /* either T_INT or T_REAL */
  59. };
  60.  
  61. struct var {
  62.   struct var *next;
  63.   struct val val;
  64.   char   *name;
  65. };
  66.  
  67. struct tok {
  68.   struct tok *next;
  69.   struct var *var;
  70.   struct val val;
  71.   char   token, funcid, *name, *name_end;
  72. };
  73.  
  74.  
  75. /*** GLOBALS ***/
  76.  
  77. /* variable table */
  78. struct var *vartable;
  79.  
  80. /* table to do [char -> token type] */
  81. char scantable[UCHAR_MAX+1];
  82.  
  83. /* table of function names */
  84. char *functable[] = {
  85.   "acos", "asin", "atan", "cos", "cosh", "exp", "ln", "log",
  86.   "sin", "sinh", "sqr", "sqrt", "tan", "tanh", NULL
  87. };
  88.  
  89.  
  90.  
  91. /*** PROTOTYPES ***/
  92.  
  93. /* front-end */
  94. int evaluate(char *string, struct val **valptr);
  95.  
  96. /* tokenization */
  97. void init_tokenizer();
  98. int tokenize(char **string, struct tok **listptr);
  99. int scan_number(char **stringptr, struct val *valptr);
  100.  
  101. /* evaluation */
  102. int reset_variables();
  103. struct var *get_var(char *name);
  104. struct var *new_var(char *name, struct val *value);
  105. int precedence(struct tok *t);
  106. int eval(struct tok *list, struct val *resultptr);
  107.  
  108. /* utility functions */
  109. int same_str(const char *a, const char *b);
  110. int same_str_len(const char *a, const char *b, int len);
  111. void *allocmem(size_t len);
  112. void freeallmem();
  113.  
  114.  
  115. /*** FRONT-END ***/
  116.  
  117. int Calculate(char *string, long *intres, double *realres, int *error) {
  118.   struct val *res;
  119.   int err = evaluate(string, &res);
  120.   int type = res->type;
  121.  
  122.   if (error)   *error   = err;
  123.   if (intres)  *intres  = (type == T_INT)  ? res->ival : (long)   res->rval;
  124.   if (realres) *realres = (type == T_REAL) ? res->rval : (double) res->ival;
  125.   return type;
  126. }
  127.  
  128. int evaluate(char *string, struct val **valptr) {
  129.   int error, more;
  130.   struct tok *list;
  131.   struct val result = { T_INT, 0, 0.0 };
  132.   char *s;
  133.  
  134.   *valptr = &result;
  135.  
  136.   if (!string) return ERROR_SYNTAX;
  137.   if (!(s = allocmem(strlen(string) + 1))) return ERROR_NOMEM;
  138.   strcpy(s, string);
  139.  
  140.   init_tokenizer();
  141.  
  142.   if ((error = reset_variables()) == RESULT_OK) {
  143.     while (*s) {
  144.       if ((error = tokenize(&s, &list)) != RESULT_OK) break;
  145.       if ((error = eval(list, &result)) != RESULT_OK) break;
  146.     }
  147.   }
  148.  
  149.   freeallmem();
  150.   return error;
  151. }
  152.  
  153.  
  154.  
  155.  
  156. /**** TOKENIZATION ***/
  157.  
  158. void init_tokenizer() {
  159.   int i;
  160.  
  161.   for (i = 0; i <= UCHAR_MAX; i++)
  162.     scantable[i] =
  163.       isalpha(i) ? TK_VAR :
  164.      (isdigit(i) ? TK_VAL :
  165.      (isspace(i) ? TK_SKIP :
  166.                    TK_ERROR));
  167.  
  168.   scantable['+'] = TK_ADD;
  169.   scantable['-'] = TK_SUB;
  170.   scantable['*'] = TK_MUL;  /* also '**' = TK_POW */
  171.   scantable['/'] = TK_DIV;
  172.   scantable['%'] = TK_MOD;
  173.   scantable['$'] = TK_VAL;  /* '$' starts a hexadecimal value */
  174.   scantable['.'] = TK_VAL;  /* '.' starts a fractional value */
  175.   scantable['('] = TK_OPEN;
  176.   scantable[')'] = TK_CLOSE;
  177.   scantable[';'] = TK_BREAK;
  178.   scantable['='] = TK_ASSN; /* also '==' = TK_EQ */
  179.   scantable['~'] = TK_BNOT;
  180.   scantable['^'] = TK_BXOR;
  181.   scantable['&'] = TK_BAND; /* also '&&' = TK_AND */
  182.   scantable['|'] = TK_BOR;  /* also '||' = TK_OR */
  183.   scantable['!'] = TK_NOT;  /* also '!=' = TK_NE */
  184.   scantable['<'] = TK_LT;   /* also '<<' = TK_SHL, '<=' = TK_LE */
  185.   scantable['>'] = TK_GT;   /* also '>>' = TK_SHR, '>=' = TK_GE */
  186. }
  187.  
  188.  
  189. int tokenize(char **string, struct tok **listptr) {
  190.   struct tok *list;
  191.   int idx = 0, i, len;
  192.   char *s, *name, c, c2, nt;
  193.  
  194.   /* allocate a block of memory to hold the maximum amount of tokens */
  195.   i = strlen(*string) + 1;
  196.   list = (struct tok *) allocmem(i * sizeof(struct tok));
  197.   if (!list) return ERROR_NOMEM;
  198.  
  199.   for (s = *string; *s; s++) {
  200.     /* get token type of character and store into list */
  201.     c = list[idx].token = scantable[* (unsigned char *) s];
  202.  
  203.     /* break out of the for loop on TK_BREAK */
  204.     if (c == TK_BREAK) { s++; break; }
  205.  
  206.     switch (c) {
  207.     case TK_ERROR:
  208.       return ERROR_SYNTAX;
  209.  
  210.     case TK_SKIP:
  211.       break;
  212.  
  213.     /* most symbol-tokens fall under this one - nothing much to do */
  214.     case TK_OPEN: case TK_CLOSE: case TK_ADD: case TK_SUB:
  215.     case TK_MUL: case TK_DIV: case TK_MOD: case TK_BAND: case TK_BOR:
  216.     case TK_BXOR: case TK_BNOT: case TK_NOT: case TK_LT: case TK_GT:
  217.  
  218.       /* check for 'double character' tokens */
  219.       c2 = s[1];
  220.       nt = 0;
  221.       if (c == TK_MUL  && c2 == '*') nt = TK_POW;
  222.       if (c == TK_BAND && c2 == '&') nt = TK_AND;
  223.       if (c == TK_BOR  && c2 == '|') nt = TK_OR;
  224.       if (c == TK_NOT  && c2 == '=') nt = TK_NE;
  225.       if (c == TK_LT   && c2 == '=') nt = TK_LE;
  226.       if (c == TK_LT   && c2 == '<') nt = TK_SHL;
  227.       if (c == TK_GT   && c2 == '=') nt = TK_GE;
  228.       if (c == TK_GT   && c2 == '>') nt = TK_SHR;
  229.       if (nt) { list[idx].token = nt; s++; }
  230.  
  231.       idx++;
  232.       break;
  233.  
  234.     case TK_ASSN:
  235.       /* '=' = TK_ASSN, '==' = TK_EQ */
  236.       if (s[1] == '=') { list[idx++].token = TK_EQ; s++; break; }
  237.  
  238.       /* if the last token was a variable, change it to an assignment */
  239.       if (idx <= 0 || list[idx-1].token != TK_VAR) return ERROR_SYNTAX;
  240.       list[idx-1].token = TK_ASSN;
  241.       break;
  242.  
  243.     case TK_VAL:
  244.       if (!scan_number(&s, &list[idx++].val)) return ERROR_SYNTAX;
  245.       s--; /* wind back one for the loop's iterator */
  246.       break;
  247.  
  248.     case TK_VAR:
  249.       list[idx].name = name = s;
  250.       while (isalpha((int) s[1])) s++; /* skip to end of string */
  251.       list[idx].name_end = s+1;
  252.       len = s+1 - name;
  253.  
  254.       /* look for matching function */
  255.       for (i = 0; functable[i]; i++) {
  256.         char *fname = functable[i];
  257.         if (same_str_len(name, fname, len) && strlen(fname) == len) {
  258.           list[idx].token  = TK_FUNC;
  259.           list[idx].funcid = i;
  260.           break;
  261.         }
  262.       }
  263.       idx++;
  264.       break;
  265.     }
  266.   }
  267.  
  268.   /* write back the final position of the tokenizer - either pointing at
  269.    * a null character, or the next expression to go */
  270.   *string = s;
  271.  
  272.   /* lace up the tokens and null-terminate the strings */
  273.   if (idx > 0) {
  274.     for (i = 0; i < idx; i++) {
  275.       list[i].next = &list[i+1];
  276.       if (list[i].token == TK_VAR || list[i].token == TK_ASSN)
  277.         *(list[i].name_end) = '\0';
  278.     }
  279.     list[idx-1].next = NULL;
  280.     *listptr = list;
  281.   }
  282.   else {
  283.     *listptr = NULL;
  284.   }
  285.  
  286.   return RESULT_OK;
  287. }
  288.  
  289.  
  290. /* scans some text into a value */
  291. int scan_number(char **stringptr, struct val *valptr) {
  292.   struct val v = { T_INT, 0, 0.0 };
  293.   char *s = *stringptr;
  294.   int c;
  295.   double dp;
  296.  
  297.   /* test to see if it's a hex number */
  298.   if (s[0] == '$' || (s[0] == '0' && s[1] == 'x')) {
  299.     s += (s[1] == 'x') ? 2 : 1;
  300.     *stringptr = s;
  301.  
  302.     for (; isxdigit(c = (int) *s); s++)
  303.       v.ival = (v.ival << 4)
  304.         + (isdigit(c) ? c-'0'      : 0)
  305.         + (isupper(c) ? c-'A' + 10 : 0)
  306.         + (islower(c) ? c-'a' + 10 : 0);
  307.   }
  308.  
  309.   /* must be a decimal integer or real */
  310.   else {
  311.     for (; isdigit(c = (int) *s); s++) v.ival = (v.ival * 10) + c-'0';
  312.     if (*s == '.') {
  313.       *stringptr = ++s;
  314.       v.type = T_REAL;
  315.       v.rval = (double) v.ival;
  316.       for (dp = 0.1; isdigit(c = (int) *s); s++, dp /= 10.0)
  317.         v.rval += dp * (double) (c-'0');
  318.     }
  319.   }
  320.  
  321.   /* if no numeric chars have been read, it's a dud - return FAIL */
  322.   if (s == *stringptr) return 0;
  323.  
  324.   /* otherwise, update position and return SUCCESS */
  325.   *stringptr = s;
  326.   *valptr = v;
  327.   return 1;
  328. }
  329.  
  330.  
  331. /*** EVALUATION ***/
  332.  
  333. /* resets the variable table to just the default variables - pi */
  334. int reset_variables() {
  335.   struct val v;
  336.   vartable = NULL;
  337.   v.type = T_REAL;
  338.   v.rval = 4.0 * atan(1.0);
  339.   return (new_var("pi", &v)) ? RESULT_OK : ERROR_NOMEM;
  340. }
  341.  
  342. /* gets a variable out of the variable table */
  343. struct var *get_var(char *name) {
  344.   struct var *v;
  345.   for (v=vartable; v; v=v->next) if (same_str(v->name, name)) return v;
  346.   return NULL;
  347. }
  348.  
  349. /* creates a new variable in the variable table */
  350. struct var *new_var(char *name, struct val *value) {
  351.   struct var *v = (struct var *) allocmem(sizeof(struct var));
  352.   if (!v) return NULL;
  353.   v->name = name;
  354.   v->val  = *value;
  355.   v->next = vartable;
  356.   vartable = v;
  357.   return v;
  358. }
  359.  
  360. /* returns the precedence of a token */
  361. int precedence(struct tok *t) {
  362.   switch (t->token) {
  363.   case TK_MULI:                            return 14;
  364.   case TK_NEG:    case TK_NOT:    case TK_BNOT:            return 13;
  365.   case TK_POW:                            return 12;
  366.   case TK_MUL:    case TK_DIV:    case TK_MOD:            return 11;
  367.   case TK_ADD:    case TK_SUB:                    return 10;
  368.   case TK_SHL:    case TK_SHR:                    return 9;
  369.   case TK_LT:    case TK_GT:    case TK_LE:    case TK_GE:    return 8;
  370.   case TK_EQ:    case TK_NE:                    return 7;
  371.   case TK_BAND:                            return 6;
  372.   case TK_BOR:    case TK_BXOR:                    return 5;
  373.   case TK_AND:    case TK_OR:                    return 4;
  374.   case TK_ASSN:                            return 3;
  375.   case TK_FUNC:                            return 2;
  376.   case TK_OPEN:    case TK_CLOSE:                    return 1;
  377.   }
  378.   return 0;
  379. }
  380.  
  381. int eval(struct tok *list, struct val *resultptr) {
  382.   struct val newval = { T_INT, 0, 0.0 }, *valstk, *x, *y;
  383.   struct tok open, close, *l, *r, *t, **opstk;
  384.   char *vtxt, lt, rt, token;
  385.   int vstk, ostk, vcnt = 0, ocnt = 0;
  386.   double xr, yr, rr;
  387.   long xi, yi, ri;
  388.  
  389.   /* clear result before we do anything - and no tokens is no result */
  390.   *resultptr = newval;
  391.   if (!list) return RESULT_OK;
  392.  
  393.  
  394.   /* CONVERSION OF RAW TOKENS INTO COMPLETE INFIX EXPRESSION */
  395.  
  396.   /* wrap the token list in a pair of parentheses */
  397.   for (t = list; t->next; t = t->next); t->next = &close;
  398.   close.next = NULL; open.next = list; list = &open;
  399.   close.token = TK_CLOSE; open.token  = TK_OPEN;
  400.  
  401.   /* insert and change tokens as neccessary */
  402.   for (l=list, r=l->next; r->next; l=r, r=r->next) {
  403.     lt = l->token;
  404.     rt = r->token;
  405.  
  406.     /* convert TK_SUBs that should be unary into TK_NEGs */
  407.     if (rt == TK_SUB && lt != TK_CLOSE && lt != TK_VAR && lt != TK_VAL)
  408.       r->token = TK_NEG;
  409.  
  410.     /* insert implicit multiplication tokens */
  411.     if ((lt == TK_VAR || lt == TK_VAL || lt == TK_CLOSE)
  412.     && (rt == TK_VAR || rt == TK_VAL || rt == TK_OPEN || rt == TK_FUNC)) {
  413.       if (lt == rt) return ERROR_SYNTAX;
  414.       if (!(t=(struct tok *)allocmem(sizeof(struct tok)))) return ERROR_NOMEM;
  415.       t->token = TK_MULI; l->next = t; t->next = r;
  416.     }
  417.   }
  418.  
  419.   /* VARIABLE CHECKING */
  420.  
  421.   vcnt = ocnt = 0;
  422.   for (t = list; t; t = t->next) {
  423.     lt = t->token;
  424.  
  425.     /* count the number of values and operators */
  426.     if (lt == TK_VAR || lt == TK_VAL) vcnt++; else ocnt++;
  427.  
  428.     /* if assigned variables don't exist, create a new blank one */
  429.     if (lt == TK_ASSN) {
  430.       if (!(t->var = get_var(t->name)))
  431.         if (!(t->var = new_var(t->name, &newval)))
  432.           return ERROR_NOMEM;
  433.     }
  434.  
  435.     /* if vars don't exist, look for them in the environment */
  436.     else if (lt == TK_VAR) {
  437.       if (!(t->var = get_var(t->name))) {
  438.         if (!(vtxt = getenv(t->name))) return ERROR_VARNOTFOUND;
  439.         if (!scan_number(&vtxt, &newval)) return ERROR_SYNTAX;
  440.         if (!(t->var = new_var(t->name, &newval))) return ERROR_NOMEM;
  441.       }
  442.     }
  443.   }
  444.  
  445.   /* ALLOCATE STACKS */
  446.  
  447.   /* allocate the operator stack and the value stack */
  448.   valstk = (struct val *)  allocmem(vcnt * sizeof(struct val));
  449.   opstk  = (struct tok **) allocmem(ocnt * sizeof(struct tok *));
  450.     if (!valstk || !opstk) return ERROR_NOMEM;
  451.  
  452.   /* set the stack pointers to '0 items on stack' */
  453.   /* (the stack pointers are always set at the topmost stack item) */
  454.   ostk = vstk = -1;
  455.  
  456.   /* MAIN EVALUATION LOOP */
  457.  
  458.   for (t = list; t; t=t->next) {
  459.     switch (t->token) {
  460.  
  461.     /* unary operators always wait until after what follows is evaluated */
  462.     /* also, open parentheses are pushed to match where close ones stop */
  463.     case TK_OPEN:
  464.     case TK_ASSN: case TK_NEG: case TK_FUNC: case TK_NOT: case TK_BNOT:
  465.       opstk[++ostk] = t; break;
  466.  
  467.     /* values go straight on the value stack */
  468.     case TK_VAL:
  469.       valstk[++vstk] = t->val;
  470.       break;
  471.  
  472.     /* variables go straight on the value stack */
  473.     case TK_VAR:
  474.       valstk[++vstk] = t->var->val;
  475.       break;
  476.  
  477.     /* this is where the action happens - all operations of a higher
  478.      * precedence are now executed. then, after that, we push the operator
  479.      * to the stack, or if it's a close paren, pull and expect an open paren
  480.      *
  481.      * it's assumed that all tokens in the token stream that aren't one of
  482.      * the previous cases must be the close bracket or a binary operator -
  483.      * that's why 'default' is used rather than all the names
  484.      */
  485.     default:
  486.       while (precedence(opstk[ostk]) > precedence(t)) {
  487.         struct tok *op = opstk[ostk--];
  488.  
  489.         /* there should always be at least a close bracket left here */
  490.         if (ostk < 0) return ERROR_SYNTAX;
  491.  
  492.         /* we assume that all operators require at least one value */
  493.         /* on the stack, and check here */
  494.         if (vstk < 0) return ERROR_SYNTAX;
  495.  
  496.         /* now we actually perform evaluations */
  497.         switch (token = op->token) {
  498.  
  499.         /* binary (int/real) -> (int/real) */
  500.         case TK_ADD: case TK_SUB: case TK_MUL: case TK_MULI:
  501.  
  502.           /* pull two values from the stack, y then x, and push 'x op y' */
  503.           if (vstk < 1) return ERROR_SYNTAX;
  504.           y = &valstk[vstk--]; x = &valstk[vstk];
  505.  
  506.           /* if both values are integer, do integer operations only */
  507.           if (x->type == T_INT && y->type == T_INT) {
  508.             xi = x->ival;
  509.             yi = y->ival;
  510.             switch (token) {
  511.             case TK_MULI:
  512.             case TK_MUL: ri = (xi * yi); break;
  513.             case TK_ADD: ri = (xi + yi); break;
  514.             case TK_SUB: ri = (xi - yi); break;
  515.             }
  516.             /* push int-value result to value stack */
  517.             x->type = T_INT;
  518.             x->ival = ri;
  519.           }
  520.           else {
  521.             /* get real values - convert if neccessary */
  522.             xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
  523.             yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
  524.  
  525.             switch (token) {
  526.             case TK_MULI:
  527.             case TK_MUL: rr = (xr * yr); break;
  528.             case TK_ADD: rr = (xr + yr); break;
  529.             case TK_SUB: rr = (xr - yr); break;
  530.             }
  531.             /* push real-value result to value stack */
  532.             x->type = T_REAL;
  533.             x->rval = rr;
  534.           }
  535.           break;
  536.  
  537.  
  538.  
  539.         /* binary (int/real) -> int */
  540.         case TK_EQ: case TK_NE: case TK_LT:
  541.         case TK_GT: case TK_LE: case TK_GE:
  542.  
  543.           if (vstk < 1) return ERROR_SYNTAX;
  544.           y = &valstk[vstk--]; x = &valstk[vstk];
  545.  
  546.           if (x->type == T_INT && y->type == T_INT) {
  547.             xi = x->ival;
  548.             yi = y->ival;
  549.             switch (token) {
  550.             case TK_EQ:  ri = (xi == yi); break;
  551.             case TK_NE:  ri = (xi != yi); break;
  552.             case TK_LT:  ri = (xi <  yi); break;
  553.             case TK_GT:  ri = (xi >  yi); break;
  554.             case TK_LE:  ri = (xi <= yi); break;
  555.             case TK_GE:  ri = (xi >= yi); break;
  556.             }
  557.           }
  558.           else {
  559.             xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
  560.             yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
  561.             switch (token) {
  562.             case TK_EQ:  ri = (xr == yr); break;
  563.             case TK_NE:  ri = (xr != yr); break;
  564.             case TK_LT:  ri = (xr <  yr); break;
  565.             case TK_GT:  ri = (xr >  yr); break;
  566.             case TK_LE:  ri = (xr <= yr); break;
  567.             case TK_GE:  ri = (xr >= yr); break;
  568.             }
  569.           }
  570.           x->type = T_INT;
  571.           x->ival = ri;
  572.           break;
  573.  
  574.  
  575.         /* binary real -> real */
  576.         case TK_DIV: case TK_POW:
  577.  
  578.           if (vstk < 1) return ERROR_SYNTAX;
  579.           y = &valstk[vstk--]; x = &valstk[vstk];
  580.           xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
  581.           yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
  582.  
  583.           if (token == TK_DIV) {
  584.             if (yr == 0) return ERROR_DIV0;
  585.             x->rval = xr / yr;
  586.           }
  587.           else {
  588.             x->rval = pow(xr, yr);
  589.           }
  590.           x->type = T_REAL;
  591.       break;
  592.  
  593.  
  594.         /* binary int -> int */
  595.         case TK_MOD: case TK_AND: case TK_OR:
  596.         case TK_BAND: case TK_BOR: case TK_BXOR:
  597.         case TK_SHL: case TK_SHR:
  598.  
  599.           if (vstk < 1) return ERROR_SYNTAX;
  600.           y = &valstk[vstk--]; x = &valstk[vstk];
  601.           xi = (x->type == T_INT) ? x->ival : (long) x->rval;
  602.           yi = (y->type == T_INT) ? y->ival : (long) y->rval;
  603.  
  604.           switch (token) {
  605.           case TK_MOD:  if (yi == 0) return ERROR_DIV0;
  606.                         ri = (xi %  yi); break;
  607.           case TK_AND:  ri = (xi && yi); break;
  608.           case TK_OR:   ri = (xi || yi); break;
  609.           case TK_BAND: ri = (xi &  yi); break;
  610.           case TK_BOR:  ri = (xi |  yi); break;
  611.           case TK_BXOR: ri = (xi ^  yi); break;
  612.           case TK_SHL:  ri = (xi << yi); break;
  613.           case TK_SHR:  ri = (xi >> yi); break;
  614.           }
  615.  
  616.           x->type = T_INT;
  617.           x->ival = ri;
  618.           break;
  619.  
  620.  
  621.  
  622.         /* unary real -> real */
  623.         case TK_FUNC:
  624.           x = &valstk[vstk];
  625.           xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
  626.           switch (op->funcid) {
  627.           case F_ACOS: xr =  acos(xr); break;
  628.           case F_ASIN: xr =  asin(xr); break;
  629.           case F_ATAN: xr =  atan(xr); break;
  630.           case F_COS:  xr =   cos(xr); break;
  631.           case F_COSH: xr =  cosh(xr); break;
  632.           case F_EXP:  xr =   exp(xr); break;
  633.           case F_LN:   xr =   log(xr); break;
  634.           case F_LOG:  xr = log10(xr); break;
  635.           case F_SIN:  xr =   sin(xr); break;
  636.           case F_SINH: xr =  sinh(xr); break;
  637.           case F_SQR:  xr =   xr * xr; break;
  638.           case F_SQRT: xr =  sqrt(xr); break;
  639.           case F_TAN:  xr =   tan(xr); break;
  640.           case F_TANH: xr =  tanh(xr); break;
  641.           }
  642.           x->rval = xr;
  643.           x->type = T_REAL;
  644.           break;
  645.  
  646.  
  647.         /* unary int -> int */
  648.         case TK_BNOT: case TK_NOT:
  649.  
  650.           x = &valstk[vstk];
  651.           xi = (x->type == T_INT) ? x->ival : (long) x->rval;
  652.           if (token == TK_BNOT) {
  653.             x->ival = ~ xi;
  654.           }
  655.           else {
  656.             x->ival = ! xi;
  657.           }
  658.           x->type = T_INT;
  659.           break;
  660.  
  661.  
  662.         /* unary (int/real) -> (int/real) */
  663.         case TK_ASSN:
  664.           op->var->val = valstk[vstk];
  665.           break;
  666.  
  667.  
  668.         /* unary (int/real) -> (int/real) */
  669.         case TK_NEG:
  670.           x = &valstk[vstk];
  671.           if (x->type == T_INT)
  672.             x->ival = - x->ival;
  673.           else
  674.             x->rval = - x->rval;
  675.           break;
  676.  
  677.         } /* end select (execution switch) */
  678.       } /* end while (precedence loop) */
  679.  
  680.       /* back to the postfixified */
  681.  
  682.       /* if we had a close paren, pull the matching open paren (error if
  683.        * we pull something else. otherwise push our new operator
  684.        */
  685.       if (t->token == TK_CLOSE) {
  686.         if (opstk[ostk--]->token != TK_OPEN) return ERROR_SYNTAX;
  687.       }
  688.       else {
  689.         opstk[++ostk] = t;
  690.       }
  691.     }
  692.   }
  693.  
  694.   /* there should be exactly one value and no operators left on the stacks */
  695.   if (vstk != 0 || ostk != -1) return ERROR_SYNTAX;
  696.  
  697.   /* return that value */
  698.   *resultptr = valstk[0];
  699.   return RESULT_OK;
  700. }
  701.  
  702.  
  703.  
  704. /*** UTILITY FUNCTIONS ***/
  705.  
  706. /* case-insensitive string comparison, TRUE or FALSE result */
  707. int same_str(const char *a, const char *b) {
  708.   if (!a || !b) return 0; /* false even if a == b == null */
  709.   if (a == b) return 1;
  710.  
  711. #ifdef HAVE_STRCASECMP
  712.   return (strcasecmp(a, b) == 0);
  713. #elif HAVE_STRCMPI
  714.   return (strcmpi(a, b) == 0);
  715. #else
  716.   while ((tolower((int)*a) == tolower((int)*b))) {
  717.     if (!*a) return 1; /* if end of both strings, return true */
  718.     a++; b++;
  719.   }
  720.   return 0; /* mismatch before end of string - return false */
  721. #endif
  722. }
  723.  
  724. int same_str_len(const char *a, const char *b, int len) {
  725.   if (!a || !b) return 0; /* false even if a == b == null */
  726.   if (len == 0) return 0;
  727.   if (a == b) return 1;
  728.  
  729. #ifdef HAVE_STRNCASECMP
  730.   return (strncasecmp(a, b, len) == 0);
  731. #elif HAVE_STRNCMPI
  732.   return (strncmpi(a, b) == 0);
  733. #else
  734.   while (--len && (tolower((int)*a) == tolower((int)*b))) {
  735.     if (!*a) return 1; /* true if both strings equal & end before len */
  736.     a++; b++;
  737.   }
  738.   /* result based on last char of allowed length */
  739.   return (tolower((int)*a) == tolower((int)*b)) ? 1 : 0;
  740. #endif
  741. }
  742.  
  743.  
  744. /* tracked memory allocation */
  745.  
  746. long *memlist = NULL;
  747.  
  748. void *allocmem(size_t len) {
  749.   long *mem = (long *) malloc(len + sizeof(long *));
  750.   if (mem) {
  751.     *(long **)mem = memlist;
  752.     memlist = mem++;
  753.   }
  754.   return (void *) mem;
  755. }
  756.  
  757. void freeallmem() {
  758.   while (memlist) {
  759.     long *next = *(long **)memlist;
  760.     free((void *) memlist);
  761.     memlist = next;
  762.   }
  763. }
  764.  
  765.  
  766. #if 0
  767. void prt(struct tok *t) {
  768.   for (; t; t=t->next) {
  769.     switch(t->token)  {
  770.     case TK_OPEN:  printf("( ");  break;
  771.     case TK_CLOSE: printf(") ");  break;
  772.  
  773.     case TK_ADD:   printf("+ ");  break;
  774.     case TK_SUB:   printf("- ");  break;
  775.     case TK_MUL:   printf("* ");  break;
  776.     case TK_MULI:  printf("*i "); break;
  777.     case TK_POW:   printf("** "); break;
  778.     case TK_DIV:   printf("/ ");  break;
  779.     case TK_MOD:   printf("%% "); break;
  780.  
  781.     case TK_EQ:    printf("== "); break;
  782.     case TK_NE:    printf("!= "); break;
  783.     case TK_LT:    printf("< ");  break;
  784.     case TK_GT:    printf("> ");  break;
  785.     case TK_LE:    printf("<= "); break;
  786.     case TK_GE:    printf(">= "); break;
  787.  
  788.     case TK_AND:   printf("&& "); break;
  789.     case TK_BAND:  printf("& ");  break;
  790.     case TK_BNOT:  printf("~ ");  break;
  791.     case TK_BOR:   printf("| ");  break;
  792.     case TK_BXOR:  printf("^ ");  break;
  793.     case TK_NEG:   printf("_ ");  break;
  794.     case TK_NOT:   printf("! ");  break;
  795.     case TK_OR:    printf("|| "); break;
  796.     case TK_SHL:   printf("<< "); break;
  797.     case TK_SHR:   printf(">> "); break;
  798.  
  799.     case TK_ASSN:  printf("%s = ", t->name); break;
  800.     case TK_FUNC:  printf("%s ", functable[t->funcid]); break;
  801.     case TK_VAL:   if (t->val.type == T_INT)
  802.                      printf("%ld ", t->val.ival);
  803.                    else
  804.                      printf("%g ", t->val.rval);
  805.                    break;
  806.  
  807.     case TK_VAR:   printf("%s ", t->name); break;
  808.     default:       printf("??(%d)", t->token); break;
  809.     }
  810.   }
  811.   printf("\n");
  812. }
  813. #endif
  814.